import { Directive, ElementRef, EventEmitter, Injector, Input, OnInit, Output, Renderer2 } from '@angular/core';
import { STComponent } from '@delon/abc/st';
import { CustomColumnComponent } from '../custom-column/custom-column.component';
import { NzModalService } from 'ng-zorro-antd/modal';
import { ArrayService, deepCopy } from '@delon/util';
import { Tjpn4Config } from '../interface/tjpn4-config';
import { getW } from '../utils/ColumnWidth';

@Directive({
	selector: '[tjpn4]',
	inputs: ['config', 'url', 'checked'],
})
export class Tjpn4StDirective implements OnInit {
	private __indexColumn = {
		title: '序号',
		width: '60',
		type: 'no',
		noIndex: (item, col, index) => {
			return (this.stCom.pi - 1) * this.stCom.ps + index + 1;
		},
		allowHid: false,
		fixed: 'left',
		resizable: false,
		sort: false,
	};
	private __columns: any[];
	private __autoLoad = false;
	private __config;
	private __showCheck = false;
	private __Expand = 'children';

	@Input()
	checked;

	get columns() {
		return this.addPX(this.__columns);
	}

	set columns(v) {
		this.__columns = this.removePX(v);
	}

	set config(v: Tjpn4Config | any) {
		this.__config = v;
		this.__showCheck = Object.keys(v).includes('checkbox');
		this.__Expand = v.expand ? v.expand : 'children';
		if (v.expand) {
			this.columns = this.initDefaultColumns([...v.columns]);
		} else {
			this.columns = this.initDefaultColumns([this.__indexColumn, ...v.columns]);
		}
		if (v.url) {
			this.stCom.data = v.url;
		} else {
			this.stCom.data = v.data;
		}
		if (v.showPage !== undefined && v.showPage === false) {
			this.stCom.page.show = false;
		}
		if (v.autoLoad !== false) {
			this.__autoLoad = true;
		}
	}

	@Output()
	clickRow = new EventEmitter<any>();

	@Output()
	dblClickRow = new EventEmitter<any>();

	@Output()
	checkedChange = new EventEmitter<any>();

	@Output()
	onLoaded = new EventEmitter<any>();

	@Output()
	loadHandlerChange = new EventEmitter<STComponent>();

	@Output()
	expendRow = new EventEmitter<any>();

	@Input()
	loadHandler: STComponent;

	stCom: STComponent;

	timer;

	constructor(private injector: Injector, private el: ElementRef, private r2: Renderer2, private modelService: NzModalService, private aryService: ArrayService) {
		this.stCom = injector.get(STComponent);
		this.stCom.clickRowClassName = {
			fn: () => 'highlight_st_row',
			exclusive: true,
		};

		this.stCom.size = 'small';

		this.stCom.req.process = (ro) => {
			if (!this.__config.showPage) {
				delete ro.params['size'];
				delete ro.params['current'];
			}
			return ro;
		};

		this.stCom.res.process = (d, rd) => {
			if (this.__config && Object.hasOwn(this.__config, 'checkbox')) {
				const key = this.__config.checkbox;
				const m = this.ls2Map(this.checked, key);
				d.every((i) => {
					i.checked = Object.hasOwn(m, i[key]);
					if (i.checked) {
						m[i[key]] = i;
					}
					return i;
				});

				rd.records.every((i) => {
					i.checked = Object.hasOwn(m, i[key]);
					if (i.checked) {
						m[i[key]] = i;
					}
					return i;
				});

				this.checked = Object.values(m);
				this.checkedChange.emit(this.checked);
			}

			return rd.records || rd;
		};

		el.nativeElement.className = el.nativeElement.className + ' tjpn4_st';
		el.nativeElement.style.flex = 1;
		// el.nativeElement.parentNode.style.display = 'flex';
		// el.nativeElement.parentNode.style.flexDirection = 'column';

		this.stCom.change.subscribe(({ type, resize, loaded, click, dblClick, expand, checkbox }) => {
			if ('resize' === type) {
				const w = String(resize['width']).replaceAll('px', '');
				this.getCol(resize['indexKey']).width = w;
				this.stopSortOnResize();
				this.reRender2();
			}
			if ('ps' === type) {
				this.stCom.pi = 1;
			} else if ('click' === type) {
				if (this.timer) {
					clearTimeout(this.timer);
				}
				this.timer = setTimeout(() => {
					this.clickRow.emit(click.item);
				}, 300);
			} else if ('dblClick' === type) {
				if (this.timer) {
					clearTimeout(this.timer);
				}
				this.timer = setTimeout(() => {
					this.dblClickRow.emit(dblClick.item);
				}, 300);
			} else if ('loaded' === type) {
				this.onLoaded.emit(loaded);
				loaded.forEach((i) => {
					if (i.expand) {
						this.expandChildren(i);
					}
				});
				if (loaded[0]) {
					loaded[0]._rowClassName = loaded[0]._rowClassName + ' highlight_st_row';
				}
			} else if (type === 'expand') {
				if (expand[this.__Expand]) {
					this.expandChildren(expand);
				}
			} else if (type === 'checkbox') {
				this.checked = this.appendCheck(checkbox);
				this.checkedChange.emit(this.checked);
			}
		});
	}

	ngOnInit(): void {
		if (this.__config) {
			if (this.__config.height) {
				this.stCom.scroll = {
					y: this.__config.height,
				};
			}
			this.reRender(this.__autoLoad);
		}
	}

	private expandChildren(expand) {
		const t = [...this.stCom.list];
		t.forEach((i: any, ix) => {
			i.showExpand = Object.hasOwn(i, this.__Expand);
			if (i.id === expand.id) {
				if (expand && expand[this.__Expand]) {
					if (expand.expand) {
						this.stCom.addRow(expand[this.__Expand], { index: ix + 1 });
					} else {
						this.stCom.removeRow(expand[this.__Expand]);
					}
					expand[this.__Expand].every((ii) => {
						ii.showExpand = Object.hasOwn(ii, this.__Expand);
						return ii;
					});
				}
			}
		});
	}

	private reRender(ne?) {
		this.setSX();
		this.stCom
			.resetColumns({
				columns: this.columns,
				emitReload: false || ne,
			})
			.finally(() => {
				this.renderLastTitle();
				if (!ne) {
					if (typeof this.stCom.data === 'object') {
						this.stCom.load(1);
					}
				}
				this.loadHandler = this.stCom;
				this.loadHandlerChange.emit(this.loadHandler);
			});
	}

	private reRender2() {
		this.setSX();
		this.stCom
			.resetColumns({
				columns: this.columns,
				emitReload: false,
			})
			.finally(() => {
				this.renderLastTitle();
			});
	}

	private renderLastTitle() {
		const doms = this.el.nativeElement.getElementsByTagName('thead');
		if (doms != null && doms.length > 0) {
			const doms_tr = doms[0].getElementsByTagName('tr');
			if (doms_tr != null && doms_tr.length > 0) {
				const doms_th = doms_tr[0].getElementsByTagName('th');
				const dom = doms_th.item(doms_th.length - 1);
				this.r2.setStyle(dom, 'z-index', '20')
				const div = this.r2.createElement('div');
				div.style.display = 'flex';
				const spans = dom.getElementsByTagName('span');
				if (spans[0]) {
					spans[0].style.flex = 1;
				}
				const img = this.r2.createElement('img') as HTMLImageElement;
				img.src = 'assets/img/column.svg';
				img.style.width = '15px';
				img.style.marginLeft = '5px';
				img.style.zIndex = '999';
				img.addEventListener('click', (ev) => {
					ev.stopPropagation();
					this.customColumn();
				});
				const cs = dom.children;
				for (let i = 0; i < cs.length; i++) {
					this.r2.appendChild(div, cs[i]);
				}
				this.r2.appendChild(div, img);
				this.r2.appendChild(dom, div);
			}
		}
	}

	private customColumn() {
		this.modelService
			.create({
				nzContent: CustomColumnComponent,
				nzTitle: '自定义展示',
				nzData: this.__columns,
				nzFooter: null,
				nzWidth: 800,
			})
			.afterClose.subscribe((res) => {
				if (res) {
					this.columns = [...res];
					this.reRender2();
				}
			});
	}

	private addPX(ls: any[]) {
		ls = deepCopy(ls);
		this.aryService.visitTree(ls, (i) => {
			i.width = String(i.width).replaceAll('px', '') + 'px';
		});
		return ls;
	}

	private removePX(ls: any[]) {
		ls = deepCopy(ls);
		this.aryService.visitTree(ls, (i) => {
			i.width = String(i.width).replaceAll('px', '');
		});
		return ls;
	}

	private setSX() {
		const x = this.removePX(this.__columns)
			.filter((i: any) => i.checked)
			.map((i: any) => i.width)
			.join('+');
		const w = eval(x) + 'px';
		this.stCom.scroll.x = w;
		if (this.el.nativeElement.getElementsByTagName('table').length > 0) {
			const tb = this.el.nativeElement.getElementsByTagName('table')[0];
			tb.style.width = w;
		}
	}

	private initDefaultColumns(ls: any[]) {
		ls.every((i) => {
			if (i.type === 'no' && this.__showCheck) {
				i.type = 'checkbox';
				i.title = '';
			}
			// i.width = i.width !== undefined ? i.width : '120';
			const ws = getW(i.index);
			i.width = ws !== undefined ? ws : i.width !== undefined ? i.width : '120';
			i.checked = i.checked !== undefined ? i.checked : true;
			i.allowHid = i.allowHid !== undefined ? i.allowHid : true;
			// i.sort = i.sort !== undefined ? i.sort : true;
			i.sort = false;
			i.iif = i.iif !== undefined ? i.iif : (i: any) => i.checked;
			i.className = i.className !== undefined ? i.className + ' tc' : 'tc';

			if (typeof i.checked === 'function') {
				i.checked = i.checked();
			}

			if (i.resizable === undefined) {
				i.resizable = true;
			}

			if (String(i.sort) === 'false') {
				delete i.sort;
			}

			if (i.buttons) {
				i.buttons.forEach((ii) => {
					if (ii.type === 'del') {
						ii.className = 'tjpn4_btn_del';
					}
				});
			}

			if (i.children) {
				delete i.sort;
				delete i.resizable;
				i.children = this.initDefaultColumns(i.children);
				i.width = eval(i.children.map((i: any) => i.width).join('+'));
			}

			return i;
		});

		return ls;
	}

	private getCol(colIndex) {
		let res = null;
		this.aryService.visitTree(this.__columns, (i) => {
			if (i.index === colIndex) {
				res = i;
			}
		});
		return res;
	}

	private appendCheck(ls: any[]) {
		const tmp = this.stCom.list.filter((i) => !i.checked);
		const k = this.__config.checkbox;
		const m_o = this.ls2Map(this.checked, k);

		tmp.forEach((i) => {
			delete m_o[i[k]];
		});

		ls.forEach((i) => {
			if (!Object.hasOwn(m_o, i[k])) {
				m_o[i[k]] = i;
			}
		});

		return Object.values(m_o);
	}

	private ls2Map(ls: any[], key) {
		const map = {};
		ls.forEach((i) => {
			map[i[key]] = i;
		});
		return map;
	}

	private stopSortOnResize() {
		const tt = document.getElementsByTagName('nz-table-sorters');
		for (let i = 0; i < tt.length; i++) {
			tt[i].addEventListener('click', this.stopPp);
		}
		setTimeout(() => {
			for (let i = 0; i < tt.length; i++) {
				tt[i].removeEventListener('click', this.stopPp);
			}
		}, 100);
	}

	private stopPp(e) {
		e.stopPropagation();
	}
}
